package com.validateCodeYzm.zpf.lib;

import com.fasterxml.jackson.core.type.TypeReference;
import com.github.kevinsawicki.http.HttpRequest;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang.StringUtils;


import javax.activation.MimetypesFileTypeMap;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 封装HttpRequest请求
 */
public class HttpRequestUtil extends HttpRequest {
    public HttpRequestUtil(CharSequence url, String method) throws HttpRequestException {
        super(url, method);
    }

    public HttpRequestUtil(URL url, String method) throws HttpRequestException {
        super(url, method);
    }



    public static Result<String> getKeyValue(String body,String start,String end){

        int i = body.indexOf(start);
        int i1 = body.indexOf(end);

        if(i==-1 || i1==-1){
            return Result.error("解析err字段错误:"+body);
        }

        return Result.of(body.substring(i+start.length(),i1));
    }

    private static String flattenUrl(String url,Map<String,String> params){
        String paramStr = "";
        if(Objects.nonNull(params))
            paramStr = params.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
        return url.contains("?") ? url+"&"+paramStr : url+"?"+paramStr;
    }


    public static Result<String> postResultString(String url, Map<String,String> params){
        try{

            String bodyStr = new HttpRequestUtil(url,"POST").form(params).body();
            return Result.of(bodyStr);
        }catch(Exception e){
            e.printStackTrace();
            return Result.error("request url through GET method occur error:"+url);
        }
    }

    private static Map<String,String> getResponseHeadMap(HttpURLConnection connection){
        HashMap<String, String> responseHeadMap = new HashMap<>();
        connection.getHeaderFields().forEach((k,v)->{
            if(StringUtils.isNotEmpty(k)){

                if(k.equals("Set-Cookie")){
                    String splitValue = v.stream().map(l -> l.split(";")[0]).collect(Collectors.joining(";"));
                    responseHeadMap.put(k,splitValue);
                }else{
                    responseHeadMap.put(k,StringUtils.join(v,""));
                }

            }
        });
        return responseHeadMap;
    }

    //基础的复杂请求
    public static Result<HttpResponseCollect> postWithMultipleInfo(String url,String method,Map<String,String> params,Consumer<HttpRequest> postConsumer){
        try{
            HttpRequest post = new HttpRequest(url, method);
            postConsumer.accept(post);
            String body = post.form(params).body();
            Map<String, String> hashMap = getResponseHeadMap(post.getConnection());
            HttpResponseCollect httpResponseCollect = new HttpResponseCollect(body, hashMap.getOrDefault("Set-Cookie", ""), hashMap);
            return Result.of(httpResponseCollect);
        }catch(Exception e){
            e.printStackTrace();
            return Result.error("postWithMultipleInfo:"+url);
        }
    }

    //基础的复杂请求 -> 下载文件
    public static Result<HttpResponseCollect> getMultipleFile(String url, Map<String,String> params, Consumer<HttpRequest> postConsumer, File file){
        try{
            HttpRequest getReq = new HttpRequest(url, "GET");
            postConsumer.accept(getReq);
            getReq.form(params).receive(file);
            Map<String, String> hashMap = getResponseHeadMap(getReq.getConnection());
            HttpResponseCollect httpResponseCollect = new HttpResponseCollect(hashMap.getOrDefault("Set-Cookie", ""), file);
            return Result.of(httpResponseCollect);
        }catch(Exception e){
            e.printStackTrace();
            return Result.error("getMultipleFile:"+url);
        }
    }

    //post请求携带cookie
    public static Result<String> postWithCookie(String url, Map<String,String> params,String cookie,Consumer<HttpRequest> postConsumer){
        try{
            HttpRequest postBody = new HttpRequest(url, "POST");
            postConsumer.accept(postBody);
            postBody.header("Cookie", cookie);
            String bodyStr = postBody.form(params).body();
            return Result.of(bodyStr);
        }catch(Exception e){
            e.printStackTrace();
            return Result.error("request url through GET method occur error:"+url);
        }
    }

    public static Result<String> getResultString(String url, Map<String,String> params){
        try{
            String bodyStr = new HttpRequestUtil(flattenUrl(url,params), "GET").body();
            return Result.of(bodyStr);
        }catch(Exception e){
            e.printStackTrace();
            return Result.error("request url through GET method occur error:"+url);
        }
    }


    @Deprecated
    public static  Result<String> getResultData(String url, Map<String,String> params){

        return getResultString(url,params).flatMap(bodyStr -> {

            Result<String> errStr = getKeyValue(bodyStr,"\"err\":",",\"code\"");

            if(errStr.ifNotPresent()){
                return Result.error("未查询到err关键字");
            }

            String errorMsg = errStr.getValue();

            if (!errorMsg.equals("\"\"")) {
                return Result.error("request server feedback err:" + errorMsg);
            }

            return getKeyValue(bodyStr,"\"value\":",",\"true\":true");

        });

    }

    /**
     * don't use nested generic.example List<T>,but List<Class> is fine.
     * */
    @Deprecated
    public static <T>  Result<T> getResultData(String url, Map<String,String> params,TypeReference<T> reference){
        return getResultData(url,params).flatMap(jsonStr -> JsonUtil.readMap(jsonStr,reference));
    }

    public static <T>  Result<T> getData(String url, Map<String,String> params,TypeReference<T> reference){
        return getResultString(url,params).flatMap(jsonStr -> JsonUtil.readMap(jsonStr,reference));
    }


    public static String getContentType(File file){
        String filename = file.getName();
        String contentType = new MimetypesFileTypeMap().getContentType(file);
        //contentType非空采用filename匹配默认的图片类型
        if(!"".equals(contentType)){
            if (filename.endsWith(".png")) {
                contentType = "image/png";
            }else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".jpe")) {
                contentType = "image/jpeg";
            }else if (filename.endsWith(".gif")) {
                contentType = "image/gif";
            }else if (filename.endsWith(".ico")) {
                contentType = "image/image/x-icon";
            }
        }
        if (contentType == null || "".equals(contentType)) {
            contentType = "application/octet-stream";
        }
        return contentType;
    }

    /**
     * 上传图片
     * @param urlStr
     * @param textMap
     * @param fileMap
     * contentType非空采用filename匹配默认的图片类型
     * @return 返回response数据
     */
    @SuppressWarnings("rawtypes")
    public static Result<String> formUpload(String urlStr, Map<String, String> textMap,
                                    Map<String, File> fileMap,Consumer<HttpRequest> httpRequestConsumer) {
        String res = "";
        HttpURLConnection conn = null;
        // boundary就是request头和上传文件内容的分隔符
        String BOUNDARY = "---------------------------WebKitFormBoundarykMwfNzXpkfzofPjM";
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(2000);
            conn.setReadTimeout(2000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

            httpRequestConsumer.accept(new TempProxyHttpRequest(conn));

            OutputStream out = new DataOutputStream(conn.getOutputStream());


            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                textMap.forEach((inputName,inputValue)->{
                    strBuf.append("\r\n").append("--").append(BOUNDARY)
                            .append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                });
                out.write(strBuf.toString().getBytes());
            }

            if (fileMap != null) {
                fileMap.forEach((inputName,inputValue)->{

                    if(!inputValue.exists())
                        throw  new RuntimeException("上传错误,文件不存在:["+inputValue.getPath()+"]");

                    String filename = inputValue.getName();
                    DataInputStream in = null;
                    try{
                        //没有传入文件类型，同时根据文件获取不到类型，默认采用application/octet-stream
                        String finalContentType = getContentType(inputValue);
                        StringBuffer strBuf = new StringBuffer();
                        strBuf.append("\r\n").append("--").append(BOUNDARY)
                                .append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\""
                                + inputName + "\"; filename=\"" + filename
                                + "\"\r\n");
                        strBuf.append("Content-Type:" + finalContentType + "\r\n\r\n");
                        out.write(strBuf.toString().getBytes());
                        in = new DataInputStream(new FileInputStream(inputValue));
                        int bytes = 0;
                        byte[] bufferOut = new byte[1024];
                        while ((bytes = in.read(bufferOut)) != -1) {
                            out.write(bufferOut, 0, bytes);
                        }
                    }catch (Exception e){
                        throw new RuntimeException("写入文件错误：["+filename+"]");
                    }finally {
                        if(in !=null) {
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        ;
                    }
                });
            }


            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
            // 读取返回数据
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            System.out.println("发送POST请求出错。" + urlStr);
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return Result.of(res);
    }


    private String post(String postURL,String name,String age) throws Exception{
        PostMethod postMethod = new PostMethod(postURL) ;
        postMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8") ;
        //参数设置，需要注意的就是里边不能传NULL，要传空字符串
        NameValuePair[] data = {
                new NameValuePair("name",name),
                new NameValuePair("age",age)
        };
        postMethod.setRequestBody(data);
        org.apache.commons.httpclient.HttpClient httpClient = new org.apache.commons.httpclient.HttpClient();
        httpClient.executeMethod(postMethod);
        String result = postMethod.getResponseBodyAsString() ;
        return result;
    }

//    private Result<String> postUrlEncode(String postURL,Map<String,String> paramMap,Map<String,String> formMap,Consumer<PostMethod> postMethodConsumer) {
//        PostMethod postMethod = new PostMethod(postURL) ;
//        postMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8") ;
//        postMethodConsumer.accept(postMethod);
//        String urlWithParam = flattenUrl(postURL, paramMap);
//
//
//        formMap.entrySet().stream().map()
//
//
//        postMethod.setRequestBody(data);
//        org.apache.commons.httpclient.HttpClient httpClient = new org.apache.commons.httpclient.HttpClient();
//        httpClient.executeMethod(postMethod);
//        String result = postMethod.getResponseBodyAsString() ;
//        return result;
//    }

    public static String postUrlEncode(String postURL,Map<String,String> paramMap,Map<String,String> formMap,Consumer<HttpRequest> httpRequestConsumer) {
        HttpRequest httpRequest = HttpRequest.post(flattenUrl(postURL, paramMap));
        httpRequestConsumer.accept(httpRequest);
        return httpRequest.form(formMap).body();
    }
}
